/**
 * This file is part of SourceCodeMetrics project.
 * 
 * Copyright (C) 2012 Krystian Warzocha
 *
 * SourceCodeMetrics is free software: you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by the 
 * Free Software Foundation, either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * SourceCodeMetrics is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with 
 * SourceCodeMetrics. If not, see http://www.gnu.org/licenses/.
 */

package org.sourcecodemetrics.view.top;

import org.sourcecodemetrics.measurer.api.IProject;
import java.io.File;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JTable;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.TableColumn;
import org.sourcecodemetrics.view.top.nodes.MyTableCellRenderer;
import org.sourcecodemetrics.view.top.nodes.ProjectNode;
import org.sourcecodemetrics.view.options.limitations.MetricConfigurations;
import org.netbeans.api.project.Project;
import org.openide.util.LookupEvent;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import org.netbeans.api.settings.ConvertAsProperties;
import org.netbeans.swing.etable.ETableColumnModel;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.view.OutlineView;
import org.openide.nodes.Node;
import org.openide.util.Lookup;
import org.openide.util.LookupListener;
import org.openide.util.Utilities;
import org.sourcecodemetrics.report.generators.ReportGeneratorImpl;
import org.sourcecodemetrics.view.top.nodes.ClassNode;
import org.sourcecodemetrics.view.top.nodes.PackageNode;

/**
 * Top component which displays the metrics. 
 */
@ConvertAsProperties(dtd = "-//metrics.view//MetricsWindow//EN",
autostore = false)
@TopComponent.Description(preferredID = "MetricsWindowTopComponent",
iconBase = "metrics/view/magnifier.gif",
persistenceType = TopComponent.PERSISTENCE_NEVER)
@TopComponent.Registration(mode = "explorer", openAtStartup = false)
@ActionID(category = "Window", id = "metrics.view.MetricsWindowTopComponent")
@ActionReferences({
    @ActionReference(path = "Menu/Window", position = 500),
    @ActionReference(path = "Shortcuts", name = "D-9")
})
@TopComponent.OpenActionRegistration(displayName = "#CTL_MetricsWindowAction",
preferredID = "MetricsWindowTopComponent")
public final class MetricsWindowTopComponent extends TopComponent implements ExplorerManager.Provider, LookupListener {

    public MetricsWindowTopComponent() {
        initComponents();
        setName(NbBundle.getMessage(MetricsWindowTopComponent.class, "CTL_MetricsWindowTopComponent"));
        setToolTipText(NbBundle.getMessage(MetricsWindowTopComponent.class, "HINT_MetricsWindowTopComponent"));

        // Package metrics
        for (Map.Entry<String, String> e : MetricsNames.packageMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Class metrics
        for (Map.Entry<String, String> e : MetricsNames.class1Metrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }
        for (Map.Entry<String, String> e : MetricsNames.class2Metrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Method metrics
        for (Map.Entry<String, String> e : MetricsNames.methodMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Common metrics
        for (Map.Entry<String, String> e : MetricsNames.commonMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        setColumnWidth();

        // turn off the autoresize of the columns
        ovMetrics.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

        // setting the custom cell renderer
        setCellRenderer();
        em.setRootContext(new ProjectNode(null));
        setMessage(false, "No projects have been measured yet.");
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        bgMetricsGroup = new javax.swing.ButtonGroup();
        mainPanel = new javax.swing.JPanel();
        bnReport = new javax.swing.JButton();
        ovMetrics = new OutlineView("Tree");
        lbMessage = new javax.swing.JLabel();
        bnCollapse = new javax.swing.JButton();
        bnExpand = new javax.swing.JButton();
        pnScope = new javax.swing.JPanel();
        bnAllMetrics = new javax.swing.JToggleButton();
        bnPackageMetrics = new javax.swing.JToggleButton();
        bnClass1Metrics = new javax.swing.JToggleButton();
        bnClass2Metrics = new javax.swing.JToggleButton();
        bnMethodMetrics = new javax.swing.JToggleButton();

        org.openide.awt.Mnemonics.setLocalizedText(bnReport, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnReport.text")); // NOI18N
        bnReport.setToolTipText(org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnReport.toolTipText")); // NOI18N
        bnReport.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bnReportActionPerformed(evt);
            }
        });

        ovMetrics.setAutoscrolls(true);
        ovMetrics.setNodePopupFactory(null);

        org.openide.awt.Mnemonics.setLocalizedText(lbMessage, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.lbMessage.text")); // NOI18N

        org.openide.awt.Mnemonics.setLocalizedText(bnCollapse, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnCollapse.text")); // NOI18N
        bnCollapse.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bnCollapseActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(bnExpand, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnExpand.text")); // NOI18N
        bnExpand.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bnExpandActionPerformed(evt);
            }
        });

        pnScope.setBorder(javax.swing.BorderFactory.createEtchedBorder());

        bgMetricsGroup.add(bnAllMetrics);
        org.openide.awt.Mnemonics.setLocalizedText(bnAllMetrics, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnAllMetrics.text")); // NOI18N
        bnAllMetrics.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bnAllMetricsActionPerformed(evt);
            }
        });

        bgMetricsGroup.add(bnPackageMetrics);
        org.openide.awt.Mnemonics.setLocalizedText(bnPackageMetrics, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnPackageMetrics.text")); // NOI18N
        bnPackageMetrics.setToolTipText(org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnPackageMetrics.toolTipText")); // NOI18N
        bnPackageMetrics.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bnPackageMetricsActionPerformed(evt);
            }
        });

        bgMetricsGroup.add(bnClass1Metrics);
        org.openide.awt.Mnemonics.setLocalizedText(bnClass1Metrics, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnClass1Metrics.text")); // NOI18N
        bnClass1Metrics.setToolTipText(org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnClass1Metrics.toolTipText")); // NOI18N
        bnClass1Metrics.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bnClass1MetricsActionPerformed(evt);
            }
        });

        bgMetricsGroup.add(bnClass2Metrics);
        org.openide.awt.Mnemonics.setLocalizedText(bnClass2Metrics, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnClass2Metrics.text")); // NOI18N
        bnClass2Metrics.setToolTipText(org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnClass2Metrics.toolTipText")); // NOI18N
        bnClass2Metrics.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bnClass2MetricsActionPerformed(evt);
            }
        });

        bgMetricsGroup.add(bnMethodMetrics);
        org.openide.awt.Mnemonics.setLocalizedText(bnMethodMetrics, org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnMethodMetrics.text")); // NOI18N
        bnMethodMetrics.setToolTipText(org.openide.util.NbBundle.getMessage(MetricsWindowTopComponent.class, "MetricsWindowTopComponent.bnMethodMetrics.toolTipText")); // NOI18N
        bnMethodMetrics.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bnMethodMetricsActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout pnScopeLayout = new javax.swing.GroupLayout(pnScope);
        pnScope.setLayout(pnScopeLayout);
        pnScopeLayout.setHorizontalGroup(
            pnScopeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnScopeLayout.createSequentialGroup()
                .addComponent(bnAllMetrics)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(bnPackageMetrics)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(bnClass1Metrics)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(bnClass2Metrics)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(bnMethodMetrics))
        );
        pnScopeLayout.setVerticalGroup(
            pnScopeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnScopeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(bnAllMetrics)
                .addComponent(bnPackageMetrics)
                .addComponent(bnClass1Metrics)
                .addComponent(bnClass2Metrics)
                .addComponent(bnMethodMetrics))
        );

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(lbMessage)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(pnScope, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(bnCollapse)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(bnExpand)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 61, Short.MAX_VALUE)
                .addComponent(bnReport)
                .addContainerGap())
            .addComponent(ovMetrics, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 675, Short.MAX_VALUE)
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(pnScope, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(bnCollapse)
                        .addComponent(bnExpand)
                        .addComponent(bnReport))
                    .addComponent(lbMessage))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(ovMetrics, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(mainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(mainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    private void bnAllMetricsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnAllMetricsActionPerformed
        clearColumns();

        // Package metrics
        for (Map.Entry<String, String> e : MetricsNames.packageMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Class metrics
        for (Map.Entry<String, String> e : MetricsNames.class1Metrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }
        for (Map.Entry<String, String> e : MetricsNames.class2Metrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Method metrics
        for (Map.Entry<String, String> e : MetricsNames.methodMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Common metrics
        for (Map.Entry<String, String> e : MetricsNames.commonMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        setCellRenderer();
        expandAll(em.getRootContext(), true);
        setColumnWidth();
    }//GEN-LAST:event_bnAllMetricsActionPerformed

    private void bnPackageMetricsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPackageMetricsActionPerformed
        clearColumns(); // removing all of the columns

        // adding columns representing package metrics
        for (Map.Entry<String, String> e : MetricsNames.packageMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Common metrics
        for (Map.Entry<String, String> e : MetricsNames.commonMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        setCellRenderer();
        expand(em.getRootContext(), Level.PACKAGE);
        expand(em.getRootContext(), Level.PACKAGE);
        setColumnWidth();
    }//GEN-LAST:event_bnPackageMetricsActionPerformed

    private void bnMethodMetricsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnMethodMetricsActionPerformed
        clearColumns(); // removing all of the columns

        // adding columns representing method metrics
        for (Map.Entry<String, String> e : MetricsNames.methodMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Common metrics
        for (Map.Entry<String, String> e : MetricsNames.commonMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        setCellRenderer();
        expand(em.getRootContext(), Level.METHOD);
        expand(em.getRootContext(), Level.METHOD);
        setColumnWidth();
    }//GEN-LAST:event_bnMethodMetricsActionPerformed

    private void bnClass1MetricsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnClass1MetricsActionPerformed
        clearColumns(); // removing all of the columns

        // adding columns representing some of the class metrics
        for (Map.Entry<String, String> e : MetricsNames.class1Metrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        // Common metrics
        for (Map.Entry<String, String> e : MetricsNames.commonMetrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        setCellRenderer();
        expand(em.getRootContext(), Level.CLASS);
        expand(em.getRootContext(), Level.CLASS);
        setColumnWidth();
    }//GEN-LAST:event_bnClass1MetricsActionPerformed

    private void bnClass2MetricsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnClass2MetricsActionPerformed
        clearColumns(); // removing all of the columns

        // adding columns representing some of the class metrics
        for (Map.Entry<String, String> e : MetricsNames.class2Metrics.entrySet()) {
            ovMetrics.addPropertyColumn(e.getKey(), e.getKey(), e.getValue());
        }

        setCellRenderer();
        expand(em.getRootContext(), Level.CLASS);
        expand(em.getRootContext(), Level.CLASS);
        setColumnWidth();
    }//GEN-LAST:event_bnClass2MetricsActionPerformed

    private void bnReportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnReportActionPerformed
        JFileChooser jfc = new JFileChooser();
        jfc.setMultiSelectionEnabled(false);
        jfc.setAcceptAllFileFilterUsed(false);
        jfc.setFileFilter(new FileNameExtensionFilter("Excel file", "xls", "xls"));
        if (jfc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            File file = jfc.getSelectedFile();
            String filePath = file.getAbsolutePath();
            if (!filePath.endsWith(".xls")) {
                filePath += ".xls";
            }
            ReportGeneratorImpl rgi = new ReportGeneratorImpl();
            rgi.generateReport(MetricsAction.getProject(), filePath);
        }
    }//GEN-LAST:event_bnReportActionPerformed

    private void bnCollapseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCollapseActionPerformed
        expandAll(em.getRootContext(), false);
    }//GEN-LAST:event_bnCollapseActionPerformed

    private void bnExpandActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnExpandActionPerformed
        expandAll(em.getRootContext(), true);
    }//GEN-LAST:event_bnExpandActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.ButtonGroup bgMetricsGroup;
    private javax.swing.JToggleButton bnAllMetrics;
    private javax.swing.JToggleButton bnClass1Metrics;
    private javax.swing.JToggleButton bnClass2Metrics;
    private javax.swing.JButton bnCollapse;
    private javax.swing.JButton bnExpand;
    private javax.swing.JToggleButton bnMethodMetrics;
    private javax.swing.JToggleButton bnPackageMetrics;
    private javax.swing.JButton bnReport;
    private javax.swing.JLabel lbMessage;
    private javax.swing.JPanel mainPanel;
    private org.openide.explorer.view.OutlineView ovMetrics;
    private javax.swing.JPanel pnScope;
    // End of variables declaration//GEN-END:variables
    private ExplorerManager em = new ExplorerManager();
    private static MetricsWindowTopComponent self = null;

    private void clearColumns() {
        // Common metrics
        for (Map.Entry<String, String> e : MetricsNames.commonMetrics.entrySet()) {
            ovMetrics.removePropertyColumn(e.getKey());
        }

        // Method metrics
        for (Map.Entry<String, String> e : MetricsNames.methodMetrics.entrySet()) {
            ovMetrics.removePropertyColumn(e.getKey());
        }

        // Class metrics
        for (Map.Entry<String, String> e : MetricsNames.class1Metrics.entrySet()) {
            ovMetrics.removePropertyColumn(e.getKey());
        }
        for (Map.Entry<String, String> e : MetricsNames.class2Metrics.entrySet()) {
            ovMetrics.removePropertyColumn(e.getKey());
        }

        // Package metrics
        for (Map.Entry<String, String> e : MetricsNames.packageMetrics.entrySet()) {
            ovMetrics.removePropertyColumn(e.getKey());
        }
    }

    private void setColumnWidth() {
        // set the width of columns depicting metrics
        ETableColumnModel e = (ETableColumnModel) ovMetrics.getOutline().getColumnModel();
        for (int i = 1; i < e.getColumnCount(); i++) {
            TableColumn tc = ovMetrics.getOutline().getColumnModel().getColumn(i);
            tc.setWidth(50);
            tc.setPreferredWidth(50);
            tc.setMaxWidth(50);
            tc.setMinWidth(50);
            tc.setResizable(false);
        }

        // set the width of the first column
        TableColumn firstColumn = ovMetrics.getOutline().getColumnModel().getColumn(0);
        firstColumn.sizeWidthToFit();
        firstColumn.setWidth(300);
        firstColumn.setPreferredWidth(300);
        firstColumn.setMinWidth(300);
        firstColumn.setResizable(true);
    }

    private void setCellRenderer() {
        // setting the custom cell renderer
        ETableColumnModel e = (ETableColumnModel) ovMetrics.getOutline().getColumnModel();
        MyTableCellRenderer renderer = new MyTableCellRenderer();
        for (int i = 1; i < e.getColumnCount(); i++) {
            TableColumn tc = e.getColumn(i);
            tc.setCellRenderer(renderer);
            tc.setCellEditor(null);
        }
    }

    @Override
    public void componentOpened() {
        // load metric configurations when the component is opened
        MetricConfigurations.getMc().load();

        // registering to listen to java project selections
        result = Utilities.actionsGlobalContext().lookupResult(Project.class);
        result.addLookupListener(this);
    }

    @Override
    public void componentClosed() {
        // unregistering from lookup
        result.removeLookupListener(this);
    }

    @Override
    public void resultChanged(LookupEvent le) {

        Collection<? extends Project> projects = result.allInstances();
        if (!projects.isEmpty()) {
            Project p = projects.iterator().next();
            String n = p.getProjectDirectory().getName();
            IProject ip = Projects.getMeasurements(n);

            if (ip != null) {
                setMessage(true, "");
                em.setRootContext(new ProjectNode(ip));
                setDisplayName("Source Code Metrics of " + n);
                setColumnWidth();
            } else {
                // there are no measurements yet for this project
                setMessage(false, "The metrics have not been measured for this project");

            }
        }
    }

    public void setMessage(boolean visible, String message) {
        ovMetrics.setVisible(visible);
        bnAllMetrics.setVisible(visible);
        bnClass1Metrics.setVisible(visible);
        bnClass2Metrics.setVisible(visible);
        bnMethodMetrics.setVisible(visible);
        bnPackageMetrics.setVisible(visible);
        bnReport.setVisible(visible);
        bnCollapse.setVisible(visible);
        bnExpand.setVisible(visible);
        pnScope.setVisible(visible);
        lbMessage.setText(message);

        if (visible) {
            setColumnWidth();
        }
    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // read your settings according to their version
    }

    @Override
    public ExplorerManager getExplorerManager() {
        return em;
    }

    public static MetricsWindowTopComponent getSelf() {
        if (self == null) {
            self = new MetricsWindowTopComponent();
        }
        return self;
    }

    private void expand(Node node, Level level) {
        switch (level) {
            case PACKAGE:
                if (node instanceof ProjectNode) {
                    ovMetrics.expandNode(node);
                } else {
                    ovMetrics.collapseNode(node);
                    return;
                }
                break;
            case CLASS:
                if (node instanceof ProjectNode || node instanceof PackageNode) {
                    ovMetrics.expandNode(node);
                } else {
                    ovMetrics.collapseNode(node);
                    return;
                }
                break;
            case METHOD:
                if (node instanceof ProjectNode || node instanceof PackageNode || node instanceof ClassNode) {
                    ovMetrics.expandNode(node);
                } else {
                    ovMetrics.collapseNode(node);
                    return;
                }
                break;
        }

        for (Node n : node.getChildren().getNodes()) {
            expand(n, level);
        }
    }

    private void expandAll(Node node, boolean expand) {
        if (expand) {
            ovMetrics.expandNode(node);
        } else {
            ovMetrics.collapseNode(node);
        }
        for (Node n : node.getChildren().getNodes()) {
            expandAll(n, expand);
        }
    }

    private enum Level {

        PACKAGE, CLASS, METHOD
    };
    private Lookup.Result<Project> result;
    private static final Logger logger = Logger.getLogger(MetricsWindowTopComponent.class.getName());
}
